﻿using System.Collections.Generic;
using UIKit.Common;
using System.Windows;
using System.Windows.Controls;
using System.Linq;

namespace UIKit.Controls
{
    public class ImageWallCaculator
    {
        #region Fields
        private List<IImageModel> _imageWallInfos = new List<IImageModel>();
        private List<FrameworkElement> _templatePool;
        private double[] _columnY;
        private double _columnMargin;
        private double _width;
        private int _columnCount;
        private DataTemplate _itemTemplate;
        private Canvas _itemsPanel;
        #endregion

        #region ImageWallCaculator
        public ImageWallCaculator()
        {
            _imageWallInfos = new List<IImageModel>();
        }
        #endregion

        public void InitPool()
        {
            _templatePool = new List<FrameworkElement>();
            //这个模版池的数量需要精确计算
            for (int i = 0; i < 70; i++)
            {
                FrameworkElement element = (FrameworkElement)ItemTemplate.LoadContent();
                element.Tag = false;
                _templatePool.Add(element);
            }
        }

        #region Properties
        public List<IImageModel> ImageWallInfos
        {
            get { return _imageWallInfos; }
            set { _imageWallInfos = value; }
        }

        public int ColumnCount
        {
            get { return _columnCount; }
            set
            {
                _columnCount = value;
                _columnY = new double[_columnCount];
            }
        }

        public double ColumnMargin
        {
            get { return _columnMargin; }
            set { _columnMargin = value; }
        }

        /// <summary>
        /// 控件总宽度
        /// </summary>
        public double Width
        {
            get { return _width; }
            set { _width = value; }
        }

        public double MaxHeight
        {
            get
            {
                int index = 0;
                for (int i = 1; i < ColumnCount; i++)
                {
                    if (_columnY[index] < _columnY[i])
                    {
                        index = i;
                    }
                }
                return _columnY[index];
            }
        }

        public DataTemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set { _itemTemplate = value; }
        }

        public Canvas ItemsPanel
        {
            get { return _itemsPanel; }
            set { _itemsPanel = value; }
        }
        #endregion

        #region Method
        private double GetAverageWidth()
        {
            return (_width - ColumnMargin * (ColumnCount + 1)) / ColumnCount;
        }

        private int GetLowestIndex()
        {
            int index = 0;
            for (int i = 1; i < ColumnCount; i++)
            {
                if (_columnY[index] > _columnY[i])
                {
                    index = i;
                }
            }
            return index;
        }

        #endregion

        internal void AddItem(IImageModel imageInfo)
        {
            int lowestIndex = GetLowestIndex();
            double width = GetAverageWidth();
            double height = width * imageInfo.ImgRatio;
            double x = (ColumnMargin + width) * lowestIndex + ColumnMargin;
            double y = _columnY[lowestIndex] + ColumnMargin;
            _columnY[lowestIndex] = y + height;
            imageInfo.Width = width;
            imageInfo.Height = height;
            imageInfo.Left = x;
            imageInfo.Top = y;
            this._imageWallInfos.Add(imageInfo);
            ShowItem(imageInfo);
        }

        internal List<IImageModel> RemoveItems(double verticalOffset)
        {
            List<IImageModel> removeItems = new List<IImageModel>();
            foreach (IImageModel imageInfo in _imageWallInfos)
            {
                double virtualY = imageInfo.Top - verticalOffset;
                if ((virtualY < -300 || virtualY > 800) && imageInfo.Showed)
                {
                    RemoveItem(imageInfo);
                    removeItems.Add(imageInfo);
                }
            }
            return removeItems;
        }

        internal void RemoveItem(IImageModel imageModel)
        {
            lock (_templatePool)
            {
                FrameworkElement template = _templatePool.Where(x => x.DataContext == imageModel && (bool)x.Tag == true).FirstOrDefault();
                template.DataContext = null;
                template.Width = 0;
                template.Height = 0;
                Canvas.SetLeft(template, 0);
                Canvas.SetTop(template, 0);
                _itemsPanel.Children.Remove(template);
                template.Tag = false;
                imageModel.Showed = false;
                _itemsPanel.Height = MaxHeight;
            }
           
        }

        internal List<IImageModel> ShowItems(double verticalOffset)
        {
            List<IImageModel> addItems = new List<IImageModel>();
            foreach (IImageModel imageInfo in _imageWallInfos)
            {
                double virtualY = imageInfo.Top - verticalOffset;
                if (virtualY >= -300 && virtualY <= 800 && !imageInfo.Showed)
                {
                    ShowItem(imageInfo);
                    addItems.Add(imageInfo);
                }
            }
            return addItems;
        }


        internal void ShowItem(IImageModel imageModel)
        {
            lock (_templatePool)
            {
                FrameworkElement template = _templatePool.Where(x => (bool)x.Tag == false).First();
                template.Tag = true;
                template.DataContext = imageModel;
                template.Width = imageModel.Width;
                template.Height = imageModel.Height;
                Canvas.SetLeft(template, imageModel.Left);
                Canvas.SetTop(template, imageModel.Top);
                _itemsPanel.Children.Add(template);
                imageModel.Showed = true;
                _itemsPanel.Height = MaxHeight;
            }
            
        }
    }
}
